很多 AI Agent 教學,會從 LangChain、LangGraph 或某個 Agent Framework 開始。
我們會先建立一個 Agent、加入幾個工具,再讓它根據使用者的問題決定要呼叫哪個工具。
這些教學可以很快做出一個 Demo,但也很容易讓人產生一個誤解:
AI Agent 的能力,主要來自更強的模型或更複雜的 Prompt。
實際上,當 Agent 開始執行真實任務後,真正困難的問題通常發生在模型之外:
這些問題不只是 Prompt Engineering。
它們屬於模型外面的執行系統,也就是這個系列要拆解的主角:
Agent Harness
先從最基本的模型呼叫開始。
response = model.generate(
"請幫我整理這個專案的程式碼"
)
print(response)
模型會接收輸入,經過推理,最後回傳一段文字。
但它沒有辦法真的打開專案、讀取檔案、執行測試或修改程式碼。
即使模型回答:
我會先查看專案結構,接著找到核心模組,最後執行測試。
它仍然只是在描述行動。
模型本身沒有:
它可以決定想做什麼,但不能單獨把決定變成真實行動。
所以,一次模型呼叫比較像:
輸入 → 模型 → 輸出
而不是一個完整的 Agent。
一個最基本的 Agent,至少需要形成一個循環:
使用者提出任務
↓
模型決定下一步
↓
Harness 執行工具
↓
工具回傳結果
↓
模型根據結果繼續判斷
↓
完成或進入下一輪
例如,使用者要求:
找出專案裡造成測試失敗的程式碼並修正。
模型可能先要求執行:
pytest
Harness 收到工具請求後,才真正執行指令,並把結果送回模型:
FAILED tests/test_user.py
Expected 200, received 500
模型看到結果後,可能接著要求讀取檔案、修改程式碼,再重新執行測試。
因此,Agent 的核心不是「模型回答得比較長」,而是:
模型的判斷可以透過外部系統持續轉換成行動、觀察與下一輪判斷。
我們可以先用一句話劃分兩者的責任:
模型負責判斷,Harness 負責環境。
模型通常負責:
Harness 通常負責:
可以把它想像成:
┌──────────────────────────────┐
│ Harness │
│ │
│ 工具、權限、記憶、狀態 │
│ 任務、Context、排程、評估 │
│ │
│ ┌────────────────┐ │
│ │ Model │ │
│ │ │ │
│ │ 理解、推理、判斷 │ │
│ └────────────────┘ │
│ │
└──────────────────────────────┘
模型位於系統中心,但完整的 Agent 架構遠大於一次模型呼叫。
Awesome Agent Architecture 目前將這些機制拆成八個層級,從最小 Agent Loop,逐步加入工具、權限、Context、Memory、背景任務、多 Agent、評估、Loop Engineering 與 Graph Engineering。
一個基本的 Agent Harness,至少需要處理四件事。
模型可以產生一個 Tool Call:
{
"name": "read_file",
"arguments": {
"path": "src/main.py"
}
}
但這段 JSON 不會自己讀取檔案。
Harness 必須:
read_file 的工具。模型選擇工具;Harness 執行工具。
工具執行完成後,結果必須加入下一輪輸入。
例如:
messages.append({
"role": "tool",
"content": "src/main.py contains 84 lines...",
"tool_call_id": tool_call.id,
})
沒有這個步驟,模型只知道自己「要求讀取檔案」,卻不知道檔案裡有什麼。
Agent 之所以可以持續工作,是因為 Harness 不斷建立這個循環:
判斷 → 行動 → 觀察 → 再判斷
假設模型要求:
rm -rf ./data
系統不應該因為模型選擇了這個工具,就直接執行。
Harness 可以先判斷:
這些限制不應該只寫在 Prompt 裡。
Prompt 可以告訴模型:
不要刪除重要檔案。
但模型仍可能誤判、忽略或錯誤理解。
真正的安全邊界應該由模型外面的程式碼執行。
模型 API 通常不會自動記住前一次呼叫。
Harness 必須保存:
messages = [
{"role": "user", "content": "修正測試"},
{"role": "assistant", "content": "我要先執行 pytest"},
{"role": "tool", "content": "2 tests failed"},
]
下一次呼叫模型時,再把相關狀態送回去。
當任務變得更長,狀態也不再只有 messages[],還可能包括:
state = {
"messages": [],
"todos": [],
"files_changed": [],
"tool_results": {},
"token_budget": 100_000,
"retry_count": 0,
"approval_state": None,
}
這些都不是模型內部自動存在的能力,而是 Harness 建立的能力。
Awesome Agent Architecture 的 Harness Thesis 也將 Harness 的基本責任整理成四點:提供行動執行環境、提供有效觀察、限制副作用,以及保存跨呼叫狀態。
因為很多 Agent 問題,最後都修錯地方。
如果模型選對工具,但 Tool Runtime 傳錯參數,問題不一定是 Prompt。
應該檢查:
如果系統允許模型直接刪除檔案,問題也不只是模型「不夠聽話」。
應該檢查:
如果重要資訊在 Context Compaction 時被刪除,單純要求模型「請記得」通常沒有用。
應該檢查:
這通常需要外部驗證,而不是再補一句:
請仔細確認答案。
更可靠的做法可能是:
當問題來自 Harness,卻一直修改 Prompt,系統往往只會變得更複雜,卻不一定更可靠。
理解 Harness 很重要,但這不代表應該把所有機制都加入 Agent。
每增加一層 Harness,都會帶來成本:
例如,舊模型可能需要非常詳細的 Planning 流程,才能完成複雜任務。
但當模型能力提升後,原本的固定規劃流程可能反而限制模型,讓它不能根據新資訊快速調整。
因此,Harness Engineering 不只是增加機制,也包括刪除不再需要的機制。
每加入一個架構層,都應該回答:
架構不是越複雜越好,而是每一層都必須有存在的理由。
Coding Agent、聊天助理和自動化 Agent,可能使用相似的模型,但它們的行為完全不同。
需要:
需要:
需要:
它們不一定是三種不同的模型。
很多時候,它們只是選擇了不同的 Harness。
這也是為什麼只學會某個 Agent Framework 的 API 還不夠。
框架可能改變,但以下架構問題仍然存在:
只要能回答這些問題,就能比較容易讀懂不同 Agent 系統。
這個系列不會直接從複雜框架開始。
我們會從一個最小 Agent Loop 出發,每天只加入一個新機制。
Model Call
↓
Agent Loop
↓
Tool Runtime
↓
Permission & Sandbox
↓
Hooks
↓
Planning
↓
Subagents
↓
Context Management
↓
Memory
↓
Tasks & Background Work
↓
Multi-Agent Coordination
↓
Observability & Evaluation
↓
Loop Engineering
↓
Graph Engineering
每一篇都會嘗試回答四個問題:
Repo 目前也使用相同方法比較 Claude Code、Hermes Agent 與 mini-swe-agent:Claude Code 用來觀察較完整的 Coding Agent Harness;Hermes Agent適合研究 Memory、Skills、Channel 與 Always-on 能力;mini-swe-agent 則展示一個接近最小化的完整 Agent Loop。
目標不是在 30 天後背下最多的新名詞。
而是當你看到任何 Agent 專案時,都能快速判斷:
哪些能力來自模型?
哪些能力來自 Harness?
哪些流程真的需要模型判斷?
哪些流程其實應該直接寫成程式碼?
一次模型呼叫只能產生輸出。
要讓模型可以持續執行任務,我們還需要一個外部系統,負責:
這個系統就是 Agent Harness。
因此,第一天最重要的概念只有一句:
模型決定要做什麼;Harness 決定這個決定如何被執行、觀察與限制。
下一篇,我們會把所有複雜機制先拿掉,只留下最小核心:
一個 Agent 到底如何持續執行,而不是回答一次就停止?
我們會從 messages[]、stop_reason 和一個簡單的 while 迴圈開始,實作最小 Agent Loop。
完整系列程式碼收錄於 GitHub:https://github.com/hardness1020/awesome-agent-architecture